package MetaClassifierAlgorithms;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;

import Alpha.LocalAlphaCalculatorClass;
import Beta.LocalBetaCalculatorClass;
import ClassificationAlgorithm.CollectiveClassificationAlgorithmClass;
import ClassificationAlgorithm.CollectiveClassificationAlgorithmFactory;
import ClassificationAlgorithm.LinkOnlyClass;
import Definitions.GraphClass;
import Definitions.NodeClass;
import Global.ConstantVariable;
import Global.ConstantVariable.Format_ConstantVariables;
import Global.DirectoryStructureAndSettingsClass;
import Global.FileExpert;
import Global.GlobalClass;
import GraphProperties.AccuracyRelatedPropsClass;
import GraphProperties.ClusteringCoefficientRelatedPropsClass;
import GraphProperties.DegreeDistributionRelatedPropsClass;
import GraphProperties.HomophilyRelatedPropsClass;
import GraphProperties.LocalAlphaRelatedPropsClass;
import GraphProperties.ShortestPathRelatedPropsClass;
import Integrity.IntegrityCheckerClass;
import Result.EvaluationClass;
import Result.ResultClass;
import Result.ResultClassListClass;
import Result.ResultIdentificationClass;
import Sampling.SamplingAbstractClass;
import Sampling.SamplingFactory;
import Sampling.SamplingTests;
import Stacking.StackingManagerClass;
import Utility.FileUtilityClass;
import Utility.WorkerUtilityClass;

public class MetaClassifierManagerClass {
	
	GraphClass graph;
	GlobalClass global;
	
	ArrayList<ResultClassListClass> metaClsresultsList;
	
	MetaClassifierManagerClass(GraphClass graph, GlobalClass global, ArrayList<ResultClassListClass> metaClsresultsList)
	{
		this.graph = graph;
		this.global = global;
		this.metaClsresultsList = metaClsresultsList;
	}
	
	//AS:Leaved just for testing. Not used since it is parallelized.
	public ResultClassListClass executeMetaClassifier(GraphClass graph, GlobalClass global)
	{

		MetaClassifierExecutionDataClass metaClassifierExecutionData = null;
		int foldNo=0;
		System.out.println("TestForLocalAlphaCalculator Start");
		
		SamplingFactory samplingFactory = new SamplingFactory();
		SamplingAbstractClass sampling=samplingFactory.createSampling(SamplingTests.createDummyParametresForSampling(ConstantVariable.Sampling_Constants.SNOWBALL_SAMPLING_METHOD), graph, global);
		for(int i=0; i<10; i++)
		{
			sampling.generateSampling(graph, i);
			System.out.println("Sampling for TestForLocalAlphaCalculator End");

			CollectiveClassificationAlgorithmFactory CCA_Factory =new CollectiveClassificationAlgorithmFactory(graph, global);

			//cca link prepared		
			CollectiveClassificationAlgorithmClass CCA_Link = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.LINK_ONLY, ConstantVariable.ExecutionParameters.SELECTED_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_LINK, sampling);
			CCA_Link.getLocalClassifierSelected().changeSecondLevelClassifierToBeUsed(ConstantVariable.ExecutionParameters.SELECTED_SECOND_LEVEL_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_LINK);


			CollectiveClassificationAlgorithmClass CCA_Content = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY, ConstantVariable.ExecutionParameters.SELECTED_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_CONTENT, sampling);
			CCA_Content.getLocalClassifierSelected().changeSecondLevelClassifierToBeUsed(ConstantVariable.ExecutionParameters.SELECTED_SECOND_LEVEL_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_CONTENT);

			CollectiveClassificationAlgorithmClass CCA_Content2 = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY, ConstantVariable.ExecutionParameters.SELECTED_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_CONTENT, sampling);
			CCA_Content.getLocalClassifierSelected().changeSecondLevelClassifierToBeUsed(ConstantVariable.WekaClassifiers.WEKA_SVM);

			
			//classifierlist preparing

			ArrayList<CollectiveClassificationAlgorithmClass> classifierList=new ArrayList<CollectiveClassificationAlgorithmClass>();
			classifierList.add(CCA_Link);
			classifierList.add(CCA_Content);
			//classifierList.add(CCA_Content2);


			//Content
			//than call alphacalculator

			metaClassifyTestForTheSpecifiedClassifiers(classifierList, graph, sampling, 0, ConstantVariable.LocalClassifier_Constants.CRISP, metaClassifierExecutionData);
		}

		return  null;
	}
	
	@SuppressWarnings("unused")
	public void metaClassifyTestForTheSpecifiedClassifiers(ArrayList<CollectiveClassificationAlgorithmClass> classifierList, GraphClass graph, SamplingAbstractClass sampling, int foldNo, String method, MetaClassifierExecutionDataClass metaClassifierExecutionData) 
	{

		GlobalClass global = sampling.getGlobal();
		//double[][] classifierRatios = new double[classifierList.size()][GlobalClass.classSize];
		//double[][] globalAlphas= new double[classifierList.size()][GlobalClass.classSize];
		
		ResultClassListClass  resultsForAVE  = metaClsresultsList.get(0);
		ResultClassListClass  resultsForMAX  = metaClsresultsList.get(1);
		ResultClassListClass  resultsForPROD = metaClsresultsList.get(2);
		ResultClassListClass  resultsForLA   = metaClsresultsList.get(3);
		ResultClassListClass  resultsForDFMM   = metaClsresultsList.get(4);
		
		ResultClassListClass  resultsForLB   = metaClsresultsList.get(5);
		
		ResultClassListClass  resultsForLAMAX   = metaClsresultsList.get(6);
		ResultClassListClass  resultsForLBMAX   = metaClsresultsList.get(7);
		
		ResultClass result=null;
		
		ArrayList<NodeClass> nodeListToBeUsedForTrain=sampling.getTrainAndValNodes();
		ArrayList<NodeClass> nodeListToBeUsedForTest=sampling.getTestNodes();
		
		int sizeOfTheClassifierList = classifierList.size();
		double[][][] probabilityDistributionMatrixForTheClassifiers = null;
		double[][][] probabilityDistributionMatrixForTheClassifiersForAllDataset = null;
		
		if(metaClassifierExecutionData.isLoaded() == false)
			metaClassifierExecutionData.createMetaExecutionResultsMatrix(ConstantVariable.CCA_ConstantVariables.NUMBER_OF_FOLDS_FOR_META_CLASSIFIER, sizeOfTheClassifierList, nodeListToBeUsedForTest.size(), global.classSize);
				
		if(ConstantVariable.ExecutionParameters.usePreviousResultsOfClsExecutionsForMetaClassifierCalculations && metaClassifierExecutionData.isLoaded())
		{			
			probabilityDistributionMatrixForTheClassifiers = metaClassifierExecutionData.getProbabilityDistributionMatrixForTheClassifiersForTheFold(foldNo);
		}				

		if(probabilityDistributionMatrixForTheClassifiers == null)
		{	
			probabilityDistributionMatrixForTheClassifiers = new double[sizeOfTheClassifierList][nodeListToBeUsedForTest.size()][global.classSize];	
			if(ConstantVariable.ExecutionParameters.outputRawResultsFiles)
				probabilityDistributionMatrixForTheClassifiersForAllDataset = new double[sizeOfTheClassifierList][graph.getDataSet().size()][global.classSize];	

			EvaluationClass eval=new EvaluationClass(sampling);

			//ArrayList<NodeClass> nodeListToBeUsedForTrain=graph.getDataSet();
			//ArrayList<NodeClass> nodeListToBeUsedForTest=graph.getDataSet();

			CollectiveClassificationAlgorithmClass cca;

			int edgeType = ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE;

			int neighbourhoodLevel;

			ArrayList<NodeClass> neighbourListOfTheNode;


			for(int i=0; i<sizeOfTheClassifierList;i++)
			{
				cca = classifierList.get(i);	
				//cca.Run(sampling, result);
				result = cca.TrainForLocalAlpha(nodeListToBeUsedForTrain, foldNo, sampling);

			}

			//TODO AS KALDIR
			//sampling.setAllTheGraphAsTrainingSetForDebuggingPurposes();

			assignRandomLabelsToTheTestNodes(sampling);			



			WorkerUtilityClass.initializeThreeDimensionalArray(probabilityDistributionMatrixForTheClassifiers, 0.0);

			for(int i=0; i<sizeOfTheClassifierList;i++)
			{
				cca = classifierList.get(i);

				int testNodeNo=0;

				if(ConstantVariable.MetaClassifier_ConstantVariables.isStabilityIssueEnabledForLinkBasedFeatures==true && cca.getName()==ConstantVariable.CCA_ConstantVariables.LINK_ONLY)
				{
					LinkOnlyClass LoCCATemp;
					LoCCATemp = (LinkOnlyClass) cca;
					LoCCATemp.BecomeStableForTheTest(sampling);
				}

				for(NodeClass k : nodeListToBeUsedForTest)
				{	
					probabilityDistributionMatrixForTheClassifiers[i][testNodeNo] = cca.TestNodeForAlpha(k, sampling, foldNo);	
					probabilityDistributionMatrixForTheClassifiersForAllDataset[i][k.getOrder()] = probabilityDistributionMatrixForTheClassifiers[i][testNodeNo];
					testNodeNo++;
				}	
				if(ConstantVariable.ExecutionParameters.outputRawResultsFiles)
					for(NodeClass k : nodeListToBeUsedForTrain)
					{	
						probabilityDistributionMatrixForTheClassifiersForAllDataset[i][k.getOrder()] = cca.TestNodeForAlpha(k, sampling, foldNo);				
					}				

				result.getEvaluationResult().createConfMatAndPrepareTheResults();			
				System.out.println("ISTE SONUC:("+i+"):"+result.getEvaluationResult().getMeasures().getAccuracy());
			}	
			if(metaClassifierExecutionData.isLoaded()==false)
				metaClassifierExecutionData.setProbabilityDistributionMatrixForTheClassifiersForTheFold(probabilityDistributionMatrixForTheClassifiers, foldNo);
		}

		analyzeQualityOfTheDivergenceOfTheClassifiers(probabilityDistributionMatrixForTheClassifiers, sampling);

		MetaClassifierFactoryClass MetaClassifierFactory = new MetaClassifierFactoryClass(graph, global, probabilityDistributionMatrixForTheClassifiers);
		
		/*AS TEST START*/
		StackingManagerClass stackingManager = new StackingManagerClass(classifierList, graph, global, sampling, foldNo);
		stackingManager.testWithStacking();
		
		result = new ResultClass(null);
		result.setSampling(sampling);			

		result.getEvaluationResult().createConfMatAndPrepareTheResults();
		
		System.out.println("ISTE SONUC(BELA_MAX):"+result.getEvaluationResult().getMeasures().getAccuracy());
		resultsForPROD.addToResultsList(result);


		/*********************************************************************/

		if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierAverageMethodEnabled)
		{		
			MetaClassifierAbstractClass MetaClassifier = MetaClassifierFactory.getMetaClassifier(ConstantVariable.MetaClassifier_ConstantVariables.Methods.MC_AVERAGE_METHOD, sampling, probabilityDistributionMatrixForTheClassifiers);
			MetaClassifier.metaClassify();

			result = new ResultClass(null);
			result.setSampling(sampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();

			System.out.println("ISTE SONUC(META_AVE):"+result.getEvaluationResult().getMeasures().getAccuracy());
			resultsForAVE.addToResultsList(result);
		}

		/*********************************************************************/

		if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierMaxMethodEnabled)
		{

			MetaClassifierAbstractClass MetaClassifier = MetaClassifierFactory.getMetaClassifier(ConstantVariable.MetaClassifier_ConstantVariables.Methods.MC_MAX_METHOD, sampling, probabilityDistributionMatrixForTheClassifiers);
			MetaClassifier.metaClassify();

			result = new ResultClass(null);
			result.setSampling(sampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();

			System.out.println("ISTE SONUC(META_MAX):"+result.getEvaluationResult().getMeasures().getAccuracy());
			resultsForMAX.addToResultsList(result);
		}
		
		/*********************************************************************/					
		if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierProductMethodEnabled)
		{
			MetaClassifierAbstractClass MetaClassifier = MetaClassifierFactory.getMetaClassifier(ConstantVariable.MetaClassifier_ConstantVariables.Methods.MC_PROD_METHOD, sampling, probabilityDistributionMatrixForTheClassifiers);
			MetaClassifier.metaClassify();

			result = new ResultClass(null);
			result.setSampling(sampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();

			System.out.println("ISTE SONUC(META_PROD):"+result.getEvaluationResult().getMeasures().getAccuracy());
			//resultsForPROD.addToResultsList(result);
		}
		
		/*********************************************************************/
		
		LocalAlphaCalculatorClass LocalAlphaCalculator;
		
		if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierLocalAlphaMethodEnabled)
		{	
			LocalAlphaCalculator = new LocalAlphaCalculatorClass(graph, global);
			
			LocalAlphaCalculator.calculateLocalAlphaForTheSpecifiedClassifiersByUsingOnlyTrainingSet(classifierList, graph, sampling, foldNo, ConstantVariable.LocalClassifier_Constants.CRISP);
			LocalAlphaCalculator.calculateLocalAlphaForTheFoldWithTheSpecifiedClassifiers(classifierList, sampling, foldNo, ConstantVariable.LocalClassifier_Constants.CRISP);

			MetaClassifierAbstractClass MetaClassifier = MetaClassifierFactory.getMetaClassifier(ConstantVariable.MetaClassifier_ConstantVariables.Methods.MC_LOCAL_ALPHA_METHOD, sampling, probabilityDistributionMatrixForTheClassifiers);
			MetaClassifier.metaClassify();

			result = new ResultClass(null);
			result.setSampling(sampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();

			System.out.println("ISTE SONUC(LA_MAX):"+result.getEvaluationResult().getMeasures().getAccuracy());
			resultsForLA.addToResultsList(result);
		}
		
		/*********************************************************************/
		
		if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierDegreeFilterMethodEnabled)
		{			
			/*LocalAlphaCalculator = new LocalAlphaCalculatorClass(graph, global);
			
			LocalAlphaCalculator.calculateLocalAlphaForTheSpecifiedClassifiersByUsingOnlyTrainingSet(classifierList, graph, global, sampling, foldNo, ConstantVariable.LocalClassifier_Constants.CRISP);
			if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierLocalAlphaMethodEnabled==false)
				LocalAlphaCalculator.calculateLocalAlphaForTheFoldWithTheSpecifiedClassifiers(classifierList, sampling, foldNo, ConstantVariable.LocalClassifier_Constants.CRISP);
				*/

			MetaClassifierAbstractClass MetaClassifier = MetaClassifierFactory.getMetaClassifier(ConstantVariable.MetaClassifier_ConstantVariables.Methods.MC_DEGREE_FILTERED_MERGE_METHOD, sampling, probabilityDistributionMatrixForTheClassifiers);
			MetaClassifier.metaClassify();

			result = new ResultClass(null);
			result.setSampling(sampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();

			System.out.println("ISTE SONUC(DFMM_MAX):"+result.getEvaluationResult().getMeasures().getAccuracy());
			resultsForDFMM.addToResultsList(result);
		}
		
		/*********************************************************************/
		
		LocalBetaCalculatorClass LocalBetaCalculator;
		
		if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierLocalBetaMethodEnabled)
		{	
			LocalBetaCalculator = new LocalBetaCalculatorClass(graph, global);
			
			//LocalBetaCalculator.calculateLocalAlphaForTheSpecifiedClassifiersByUsingOnlyTrainingSet(classifierList, graph, global, sampling, foldNo, ConstantVariable.LocalClassifier_Constants.CRISP);
			LocalBetaCalculator.calculateLocalBetaForTheFoldWithTheSpecifiedEdgeTypes(classifierList, sampling);

			MetaClassifierAbstractClass MetaClassifier = MetaClassifierFactory.getMetaClassifier(ConstantVariable.MetaClassifier_ConstantVariables.Methods.MC_LOCAL_BETA_METHOD, sampling, probabilityDistributionMatrixForTheClassifiers);
			MetaClassifier.metaClassify();

			result = new ResultClass(null);
			result.setSampling(sampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();

			System.out.println("ISTE SONUC(LB_MAX):"+result.getEvaluationResult().getMeasures().getAccuracy());
			resultsForLB.addToResultsList(result);
		}
		
		/*********************************************************************/
		
		//LocalBetaCalculatorClass LocalBetaCalculator;
		
		if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierLocalAlphaMaxMethodEnabled)
		{	
			if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierLocalAlphaMethodEnabled==false && ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierDegreeFilterMethodEnabled==false)
			{
				LocalAlphaCalculator = new LocalAlphaCalculatorClass(graph, global);

				LocalAlphaCalculator.calculateLocalAlphaForTheSpecifiedClassifiersByUsingOnlyTrainingSet(classifierList, graph, sampling, foldNo, ConstantVariable.LocalClassifier_Constants.CRISP);
				LocalAlphaCalculator.calculateLocalAlphaForTheFoldWithTheSpecifiedClassifiers(classifierList, sampling, foldNo, ConstantVariable.LocalClassifier_Constants.CRISP);
			}

			MetaClassifierAbstractClass MetaClassifier = MetaClassifierFactory.getMetaClassifier(ConstantVariable.MetaClassifier_ConstantVariables.Methods.MC_LOCAL_ALPHA_MAX_METHOD, sampling, probabilityDistributionMatrixForTheClassifiers);
			MetaClassifier.metaClassify();

			result = new ResultClass(null);
			result.setSampling(sampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();

			System.out.println("ISTE SONUC(LA_ALPHA_MAX):"+result.getEvaluationResult().getMeasures().getAccuracy());
			resultsForLAMAX.addToResultsList(result);
		}
		
		/*********************************************************************/
		
		//LocalBetaCalculatorClass LocalBetaCalculator;
		
		if(ConstantVariable.MetaClassifierExecutionParameters.isMetaClassifierLocalBetaMaxMethodEnabled)
		{	
			LocalBetaCalculator = new LocalBetaCalculatorClass(graph, global);
			
			//LocalBetaCalculator.calculateLocalAlphaForTheSpecifiedClassifiersByUsingOnlyTrainingSet(classifierList, graph, global, sampling, foldNo, ConstantVariable.LocalClassifier_Constants.CRISP);
			LocalBetaCalculator.calculateLocalBetaForTheFoldWithTheSpecifiedEdgeTypes(classifierList, sampling);

			MetaClassifierAbstractClass MetaClassifier = MetaClassifierFactory.getMetaClassifier(ConstantVariable.MetaClassifier_ConstantVariables.Methods.MC_LOCAL_BETA_MAX_METHOD, sampling, probabilityDistributionMatrixForTheClassifiers);
			MetaClassifier.metaClassify();

			result = new ResultClass(null);
			result.setSampling(sampling);			

			result.getEvaluationResult().createConfMatAndPrepareTheResults();

			System.out.println("ISTE SONUC(LA_BETA_MAX):"+result.getEvaluationResult().getMeasures().getAccuracy());
			resultsForLBMAX.addToResultsList(result);
		}
		
		if(ConstantVariable.ExecutionParameters.outputRawResultsFiles)
			outputUsefulDataForThisFold(foldNo, probabilityDistributionMatrixForTheClassifiersForAllDataset, sampling);

	}

	static void alphaAndAccuracyCalculationCompletedEvent(GraphClass graph, String datasetName)	
	{	
	}

	static void assignRandomLabelsToTheTestNodes(SamplingAbstractClass currentSampling)
	{
		Random random = new Random();
		int sizeOfClass = currentSampling.getGlobal().classList.size();

		for(int i=0; i< currentSampling.getTestNodes().size() ;i++)
		{
			int randomClass= random.nextInt(sizeOfClass);
			currentSampling.setClassLabelEstimated(currentSampling.getTestNodes().get(i), randomClass);
		}
	}
	
	public static ResultClassListClass TestInParallelStart(GraphClass graph, GlobalClass global, int numberOfFolds, SamplingAbstractClass prevSampling, ArrayList<ResultClassListClass> metaClsresultsList)
	{
		 MetaClassifierManagerClass metaClassifierManager = new MetaClassifierManagerClass(graph, global, metaClsresultsList);
		 return metaClassifierManager.TestWithWekaInParallel(graph, global, numberOfFolds, prevSampling);
	}
	
	public ResultClassListClass TestWithWekaInParallel(GraphClass graph, GlobalClass global, int numberOfFolds, SamplingAbstractClass prevSampling)
	{
		MetaClassifierTestWithWekaProcessorThreadClass[] MetaClassifierTestWithWekaProcessorPool;

		System.out.println("Meta Cls. Weka Parallel Test Start ");		

		int numberOfCores;

		int numberOfCompletedFolds=0;
		int numberOfNeededThreads=0;
		
		MetaClassifierExecutionDataClass metaClassifierExecutionData = new MetaClassifierExecutionDataClass();

		if(ConstantVariable.ExecutionParameters.usePreviousResultsOfClsExecutionsForMetaClassifierCalculations)
		{
			MetaClassifierExecutionDataClass prevMetaClassifierExecutionData = (MetaClassifierExecutionDataClass)FileUtilityClass.readObjectFromFile(IntegrityCheckerClass.getFileNameForPrevMetaClsExecutionResultsObject());
			if(prevMetaClassifierExecutionData!=null)
			{
				if(prevMetaClassifierExecutionData.checkIfAnyImportantParametersChangedComparedToPreviousExecution(metaClassifierExecutionData))
				{
					metaClassifierExecutionData = prevMetaClassifierExecutionData;
					metaClassifierExecutionData.setLoaded(true);
				}
			}
		}
		
		numberOfCores = GlobalClass.RunningValues.maximumNumberOfCPUCoresToBeUsedForTooMuchRamRequiringAndTimeConsumingTasks;
		MetaClassifierTestWithWekaProcessorPool = new MetaClassifierTestWithWekaProcessorThreadClass[numberOfCores];

		if(numberOfFolds < numberOfCores)
			numberOfNeededThreads = numberOfFolds;
		else
			numberOfNeededThreads = numberOfCores;

		String datasetName = ConstantVariable.DataSet_Constants.DATASET_NAMES[GlobalClass.RunningValues.executionFor];
		String CCA_Name = ConstantVariable.CCA_ConstantVariables.ICA;
		String samplingName = ConstantVariable.Sampling_Constants.SNOWBALL_SAMPLING_METHOD;

		ResultClassListClass resultsList = new ResultClassListClass();

		while(numberOfCompletedFolds<numberOfFolds)
		{
			if(numberOfFolds-numberOfCompletedFolds<numberOfCores)
				numberOfNeededThreads = numberOfFolds-numberOfCompletedFolds;


			for(int i=0; i<numberOfNeededThreads; i++)
			{
				ResultIdentificationClass identifier = new ResultIdentificationClass();
				identifier.setDataset(datasetName);
				identifier.setCCA(CCA_Name);
				identifier.setSampling(samplingName);
				identifier.setFold(i);
				ResultClass result = new ResultClass(identifier);

				resultsList.addToResultsList(result);

				MetaClassifierTestWithWekaProcessorPool[i] = new MetaClassifierTestWithWekaProcessorThreadClass(numberOfCompletedFolds+i, graph, global, result, metaClassifierExecutionData);
				MetaClassifierTestWithWekaProcessorPool[i].start();		
			}

			for(int i=0; i<numberOfNeededThreads; i++)
			{				
				try
				{
					MetaClassifierTestWithWekaProcessorPool[i].join();
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}	
			}			
			numberOfCompletedFolds +=numberOfNeededThreads;
		}
		if(metaClassifierExecutionData.isLoaded()==false)
			FileUtilityClass.writeObjectToFile(metaClassifierExecutionData, IntegrityCheckerClass.getFileNameForPrevMetaClsExecutionResultsObject());
		
		return resultsList;
	}

	private class MetaClassifierTestWithWekaProcessorThreadClass extends Thread
	{
		int index;     
		GraphClass graph;
		GlobalClass global;
		ResultClass result;
		MetaClassifierExecutionDataClass metaClassifierExecutionData;


		MetaClassifierTestWithWekaProcessorThreadClass(int index, GraphClass graph, GlobalClass global, ResultClass result, MetaClassifierExecutionDataClass metaClassifierExecutionData)
		{
			this.index = index;
			this.graph = graph;
			this.global = global;             
			this.result = result;
			this.metaClassifierExecutionData = metaClassifierExecutionData;
		}        

		public void run() 
		{
			SamplingFactory samplingFactory = new SamplingFactory();
			SamplingAbstractClass sampling=samplingFactory.createSampling(SamplingTests.createDummyParametresForSampling(ConstantVariable.Sampling_Constants.SNOWBALL_SAMPLING_METHOD), graph, global);

			sampling.generateSampling(graph, index);
			System.out.println("Sampling for TestForLocalAlphaCalculator End");

			result.setSampling(sampling);
			System.out.print(" name : "+ sampling.getName()+ "  size: "+ sampling.getTestNodes().size());
			sampling.getSamplingResult();


			CollectiveClassificationAlgorithmFactory CCA_Factory =new CollectiveClassificationAlgorithmFactory(graph, global);

			//cca link prepared		
			CollectiveClassificationAlgorithmClass CCA_Link = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.LINK_ONLY, ConstantVariable.ExecutionParameters.SELECTED_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_LINK, sampling);
			CCA_Link.getLocalClassifierSelected().changeSecondLevelClassifierToBeUsed(ConstantVariable.ExecutionParameters.SELECTED_SECOND_LEVEL_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_LINK);


			CollectiveClassificationAlgorithmClass CCA_Content = CCA_Factory.createCCA(ConstantVariable.CCA_ConstantVariables.CONTENT_ONLY, ConstantVariable.ExecutionParameters.SELECTED_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_CONTENT, sampling);
			CCA_Content.getLocalClassifierSelected().changeSecondLevelClassifierToBeUsed(ConstantVariable.ExecutionParameters.SELECTED_SECOND_LEVEL_LOCAL_CLASSIFIER_FOR_MERGE_CALCULATION_CONTENT);


			//classifierlist preparing

			ArrayList<CollectiveClassificationAlgorithmClass> classifierList=new ArrayList<CollectiveClassificationAlgorithmClass>();
			classifierList.add(CCA_Link);
			classifierList.add(CCA_Content);


			//Content
			//than call alphacalculator

			metaClassifyTestForTheSpecifiedClassifiers(classifierList, graph, sampling, index, ConstantVariable.LocalClassifier_Constants.CRISP, metaClassifierExecutionData);
		}
	}

	void analyzeQualityOfTheDivergenceOfTheClassifiers(double[][][] probabilityDistributionMatrixForTheClassifiers, SamplingAbstractClass sampling)
	{
		int realLabelOrder;
		int[] numberOfClassifiersEstimatedTrue = new int[probabilityDistributionMatrixForTheClassifiers[0].length];
		int[] histOfnumberOfClassifiersEstimatedTrue = new int[3];

		Arrays.fill(numberOfClassifiersEstimatedTrue, 0);
		//For all nodes
		for(int i=0; i<probabilityDistributionMatrixForTheClassifiers[0].length; i++)
		{
			realLabelOrder = sampling.getTestNodes().get(i).getClassOrder(); 
			//For all classifiers	
			for(int j=0; j<probabilityDistributionMatrixForTheClassifiers.length; j++)
			{
				if(realLabelOrder == WorkerUtilityClass.findMaxIndexForTheGivenVector(probabilityDistributionMatrixForTheClassifiers[j][i]))
					numberOfClassifiersEstimatedTrue[i]++;				
			}			

			if(numberOfClassifiersEstimatedTrue[i]!=2)
			{
				/*
				System.out.println("realLabelOrder:"+realLabelOrder);
				WorkerUtilityClass.printArray(probabilityDistributionMatrixForTheClassifiers[0][i], "Link("+i+")");
				WorkerUtilityClass.printArray(probabilityDistributionMatrixForTheClassifiers[1][i], "Content("+i+")");
				WorkerUtilityClass.printSeperator();*/

				if(numberOfClassifiersEstimatedTrue[i]==0)
				{
					histOfnumberOfClassifiersEstimatedTrue[0]++;
					//System.out.println("Hicbiri bilemedi.Gercegi:"+realLabelOrder);					
				}

				if(numberOfClassifiersEstimatedTrue[i]==1)
				{
					histOfnumberOfClassifiersEstimatedTrue[1]++;				
					//System.out.println("Biri bilemedi.Gercegi:"+realLabelOrder);
				}
				/*
				for(int j=0; j<probabilityDistributionMatrixForTheClassifiers.length; j++)
				{
					WorkerUtilityClass.printArray(probabilityDistributionMatrixForTheClassifiers[j][i], "Pr Dist:"+j);				
				}	*/				
			}
			else
				histOfnumberOfClassifiersEstimatedTrue[2]++;
		}	

		//WorkerUtilityClass.printArray(numberOfClassifiersEstimatedTrue, "numberOfClassifiersEstimatedTrue");

		WorkerUtilityClass.printArray(histOfnumberOfClassifiersEstimatedTrue, "histOfnumberOfClassifiersEstimatedTrue");

	}
	
	void outputUsefulDataForThisFold(int foldNo, double[][][] probabilityDistributionMatrixForTheClassifiers, SamplingAbstractClass sampling)
	{
		BufferedWriter out;
		
		try {
			out = DirectoryStructureAndSettingsClass.getFileOutForTheFile(FileExpert.getDirectoryNameForRawResultFileForThisFold(), FileExpert.getFileNameForRawResultFileForThisFold(foldNo, ConstantVariable.Sampling_Constants.TRAINING_STAGE), false);
			outputUsefulDataForTheFile(out, sampling, ConstantVariable.Sampling_Constants.TRAINING_STAGE, probabilityDistributionMatrixForTheClassifiers);
			out.close();


			out = DirectoryStructureAndSettingsClass.getFileOutForTheFile(FileExpert.getDirectoryNameForRawResultFileForThisFold(), FileExpert.getFileNameForRawResultFileForThisFold(foldNo, ConstantVariable.Sampling_Constants.VALIDATION_STAGE), false);
			outputUsefulDataForTheFile(out, sampling, ConstantVariable.Sampling_Constants.VALIDATION_STAGE, probabilityDistributionMatrixForTheClassifiers);
			out.close();

			out = DirectoryStructureAndSettingsClass.getFileOutForTheFile(FileExpert.getDirectoryNameForRawResultFileForThisFold(), FileExpert.getFileNameForRawResultFileForThisFold(foldNo, ConstantVariable.Sampling_Constants.TEST_STAGE), false);
			outputUsefulDataForTheFile(out, sampling, ConstantVariable.Sampling_Constants.TEST_STAGE, probabilityDistributionMatrixForTheClassifiers);
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		
	}
	
	void outputUsefulDataForTheFile(BufferedWriter out, SamplingAbstractClass sampling, int stage,  double[][][] probabilityDistributionMatrixForTheClassifiers)
	{
		ArrayList<NodeClass> nodesToBeUsed = null;
		
		if(stage == ConstantVariable.Sampling_Constants.TRAINING_STAGE)
			nodesToBeUsed = sampling.getTrainNodes();
		else if(stage==ConstantVariable.Sampling_Constants.VALIDATION_STAGE)
			nodesToBeUsed = sampling.getValNodes();
		else if(stage==ConstantVariable.Sampling_Constants.TEST_STAGE)
			nodesToBeUsed = sampling.getTestNodes();
		
		DegreeDistributionRelatedPropsClass degreeDistributionRelatedPropsCO = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).degreeDistributionRelatedProps;				
		ClusteringCoefficientRelatedPropsClass clusteringCoefficientRelatedPropsCO = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).clusteringCoefficientRelatedProps;
		HomophilyRelatedPropsClass homophilyRelatedPropsCO  = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).homophilyRelatedProps;
		LocalAlphaRelatedPropsClass localAlphaRelatedPropsCO = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).localAlphaRelatedProps;
		AccuracyRelatedPropsClass accuracyRelatedPropsCO = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).accuracyRelatedProps;
		ShortestPathRelatedPropsClass shortestPathRelatedPropsCO =  graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH).shortestPathRelatedProps;
		
		
		DegreeDistributionRelatedPropsClass degreeDistributionRelatedPropsLO = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).degreeDistributionRelatedProps;				
		ClusteringCoefficientRelatedPropsClass clusteringCoefficientRelatedPropsLO = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).clusteringCoefficientRelatedProps;
		HomophilyRelatedPropsClass homophilyRelatedPropsLO  = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).homophilyRelatedProps;
		LocalAlphaRelatedPropsClass localAlphaRelatedPropsLO = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).localAlphaRelatedProps;
		AccuracyRelatedPropsClass accuracyRelatedPropsLO = graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).accuracyRelatedProps;
		ShortestPathRelatedPropsClass shortestPathRelatedPropsLO =  graph.getPropertiesOfTheGraphWithRespectToEdgeType().get(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE).shortestPathRelatedProps;
		
		double[][] localAlphaMatrix = sampling.getLocalAlphaMatrixForTheWholeDatasetCalculatedWithThisFold();
		double[][] localBetaMatrix = sampling.getLocalBetaMatrixForTheWholeDatasetCalculatedWithThisFold();
		
		int[] neighboursHistWrtCO; 
		int[] neighboursHistWrtLO; 		

		
		String infoToBeWrittenForOneNode;
		
		for(NodeClass i:nodesToBeUsed)
		{
			infoToBeWrittenForOneNode = "";
			
			//Node id
			infoToBeWrittenForOneNode += i.getOrder();
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Node's actual label
			infoToBeWrittenForOneNode += i.getClassOrder();
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Node's predicted label(CO)
			infoToBeWrittenForOneNode += WorkerUtilityClass.findMaxIndexForTheGivenVector(probabilityDistributionMatrixForTheClassifiers[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH][i.getOrder()]);
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Node's predicted label(LO)
			infoToBeWrittenForOneNode += WorkerUtilityClass.findMaxIndexForTheGivenVector(probabilityDistributionMatrixForTheClassifiers[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE][i.getOrder()]);
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;		
			
			//CO Cls accuracy on the node
			infoToBeWrittenForOneNode += (WorkerUtilityClass.findMaxIndexForTheGivenVector(probabilityDistributionMatrixForTheClassifiers[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH][i.getOrder()])==i.getClassOrder()?1:0);
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//LO Cls accuracy on the node
			infoToBeWrittenForOneNode += (WorkerUtilityClass.findMaxIndexForTheGivenVector(probabilityDistributionMatrixForTheClassifiers[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE][i.getOrder()])==i.getClassOrder()?1:0);
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;	
			
			//CO Soft Cls Accuracies
			infoToBeWrittenForOneNode += WorkerUtilityClass.getStrFormOfTheArrayWithDelimeted(probabilityDistributionMatrixForTheClassifiers[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH][i.getOrder()], Format_ConstantVariables.CHARACTER_AS_A_DELIMETER);

			//LO Soft Cls Accuracies
			infoToBeWrittenForOneNode += WorkerUtilityClass.getStrFormOfTheArrayWithDelimeted(probabilityDistributionMatrixForTheClassifiers[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE][i.getOrder()], Format_ConstantVariables.CHARACTER_AS_A_DELIMETER);
			
			//Homophily CO
			infoToBeWrittenForOneNode += homophilyRelatedPropsCO.getHomophilyListOfTheNodes()[i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Homophily LO
			infoToBeWrittenForOneNode += homophilyRelatedPropsLO.getHomophilyListOfTheNodes()[i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Local Alpha CO
			infoToBeWrittenForOneNode += localAlphaMatrix[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH][i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Local Alpha LO
			infoToBeWrittenForOneNode += localAlphaMatrix[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE][i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Degree CO
			infoToBeWrittenForOneNode += degreeDistributionRelatedPropsCO.getDegreeListOfNodes()[i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
						
			//Degree LO
			infoToBeWrittenForOneNode += degreeDistributionRelatedPropsLO.getDegreeListOfNodes()[i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Histogram of neighbours wrt CO
			ArrayList<NodeClass> neighbours = i.getNeighbours(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH, 1);
			
			neighboursHistWrtCO = getHistForNeighbours(neighbours);
			infoToBeWrittenForOneNode += WorkerUtilityClass.getStrFormOfTheArrayWithDelimeted(neighboursHistWrtCO, Format_ConstantVariables.CHARACTER_AS_A_DELIMETER);

			//Histogram of neighbours wrt LO
			neighbours = i.getNeighbours(ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE, 1);
			
			neighboursHistWrtLO = getHistForNeighbours(neighbours);
			infoToBeWrittenForOneNode += WorkerUtilityClass.getStrFormOfTheArrayWithDelimeted(neighboursHistWrtLO, Format_ConstantVariables.CHARACTER_AS_A_DELIMETER);
						
			//CC CO
				
			infoToBeWrittenForOneNode += clusteringCoefficientRelatedPropsCO.getClusteringCoefficientListOfTheNodes()[i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
						
			//CC LO
			infoToBeWrittenForOneNode += clusteringCoefficientRelatedPropsLO.getClusteringCoefficientListOfTheNodes()[i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;		
			
			//Local Beta CO
			infoToBeWrittenForOneNode += localBetaMatrix[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE_FOR_CONTENT_GRAPH][i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Local Beta LO
			infoToBeWrittenForOneNode += localBetaMatrix[ConstantVariable.Common_ConstantVariables.DEFAULT_EDGE_TYPE][i.getOrder()];
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Betweenness Centralities CO
			infoToBeWrittenForOneNode += (shortestPathRelatedPropsCO.getBetweennessCentralities()[i.getOrder()]/shortestPathRelatedPropsCO.getNumberOfPaths());
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			//Betweenness Centralities LO
			infoToBeWrittenForOneNode += (shortestPathRelatedPropsLO.getBetweennessCentralities()[i.getOrder()]/shortestPathRelatedPropsLO.getNumberOfPaths());
			infoToBeWrittenForOneNode += Format_ConstantVariables.CHARACTER_AS_A_DELIMETER;
			
			try {
				out.write(infoToBeWrittenForOneNode);
				out.write("\r\n");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	int[] getHistForNeighbours(ArrayList<NodeClass> neighbourList)
	{
		int[] histOfNeighbours = new int[global.classSize];
		
		Arrays.fill(histOfNeighbours, 0);
		
		for(NodeClass i : neighbourList)
		{
			histOfNeighbours[i.getClassOrder()]++;			
		}
		
		return histOfNeighbours;		
	}
}
